跳到主要内容

Go 语言并发学习-sync 包-对象池

对象池 sync.Pool

sync.Pool 就是用作对象池,保存和复用临时对象,减少内存分配,降低 GC 压力。

例如 Gin 的 Context 就使用了对象池

Gin 有时需要面临大量的请求,当程序并发度非常高的情况下,短时间内需要创建大量的 Context 对象。而这些对象是都是分配在堆上的,会给 GC 造成很大压力,严重影响程序的性能,所以使用对象池来复用对象。

sync.Pool 是可伸缩的,同时也是并发安全的,其大小仅受限于内存的大小。sync.Pool 用于存储那些被分配了但是没有被使用,而未来可能会使用的值。这样就可以不用再次经过内存分配,可直接复用已有对象,减轻 GC 的压力,从而提升系统的性能。

sync.Pool 的大小是可伸缩的,高负载时会动态扩容,存放在池中的对象如果不活跃了会被自动清理。

注意,只有需要保存状态的对象才需要使用对象池,否则直接使用单例就行了

sync.Pool 的使用方式非常简单:

只需要实现 New 函数即可。对象池中没有对象时,将会调用 New 函数创建。

var studentPool = sync.Pool{
New: func() interface{} {
return new(Student) // 例如创建 Student 对象
},
}

取得对象和归还对象

stu := studentPool.Get().(*Student)
json.Unmarshal(buf, stu) // 使用线程池的对象
studentPool.Put(stu)

Get() 用于从对象池中获取对象,因为返回值是 interface{},因此需要类型转换。 Put() 则是在对象使用完毕后,返回对象池。

临时对象池的使用场景

pool 如果从名字上看,就是池的意思,但是用池来形容不够恰当,应该称为 cache,因为 Pool 里装的对象可以被无通知地被回收,所以 pool 不适合用来当 socket 连接池,注意这里指的是被 Put 回池内的对象,Get 出来的对象不会不会被回收

只有当每个对象占用内存较大时候,用 pool 才会改善性能

Reference